/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2015年3月31日
 * V4.0
 */
package com.jphenix.servlet.filter;

import com.jphenix.kernel.baseobject.instanceb.ABase;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.share.util.SFilesUtil;
import com.jphenix.standard.docs.BeanInfo;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.docs.Register;
import com.jphenix.standard.docs.Running;
import com.jphenix.standard.servlet.IFilter;
import com.jphenix.standard.servlet.IRequestManager;
import com.jphenix.standard.servlet.IResponseManager;
import com.jphenix.standard.servlet.api.IFilterConfig;

/**
 * 特殊URL处理过滤器
 * com.jphenix.servlet.filter.SpecialUrlFilter
 * 
 * 说明：
 * 
 *      1. 每一级字符串：参数问号前，用斜杠分割的字符串（可能是文件夹名，也可能是虚拟路径）
 *      2.末级字符串：最后一级的字符串，（可能是文件夹名，可能是动作路径，可能是模板文件名）
 *      3.根路径模式：如果默认动作路径的第一个字符，是斜杠（绝对路径），则为根路径模式，即：
 *      
 *          根路径模式： 将每一级字符串作为无主键参数值传入默认动作中
 *          非根路径模式：从第一级开始检测是否为文件夹，将不是文件夹的层级作为无主键参数值传入是文件夹层级的默认动作中。
 *      
 *      
 * 注意：
 * 
 *      1. 过滤器不支持变态的无扩展名动作路径，因为跟变态的无主键参数冲突
 * 
 * ********************************************************************************************
 * 1.  如果url访问的是文件夹，默认执行动作
 * 2. 如果传入参数没有主键，默认配上主键
 * 3. 判断url中问号前，斜杠后的字符串，是否为文件夹名，或虚拟路径名
 *     如果不是，将作为无主键参数传入默认动作中
 * 
 * 默认参数主键相关：
 * 
 * 获取提交的无主键参数数量    request.getParameter("_no_key_count_");
 * 获取指定无主键参数：  
 *                  request.getParameter("_no_key_0"); //第一个无主键参数
 *                  request.getParameter("_no_key_1"); //第二个无主键参数
 *                  request.getParameter("_no_key_2"); //第三个无主键参数
 *                  
 *                  
 *                  
 * 例如：
 *  1.     http://www.baidu.com/keyvalue/keyvalue2
 *      如果 keyvalue 不是文件夹
 *      假设默认动作路径为 /main.ha     
 *              实际访问的应为 http://www.baidu.com/main.ha?_no_key_count_=2&_no_key_0=keyvalue&_no_key_1=keyvalue2
 *      假设keyvalue是文件夹keyvalue2不是
 *      
 *              如果默认动作路径为 /main.ha
 *                  实际访问的应为 http://www.baidu.com/main.ha?_no_key_count=2&_no_key_0=keyvalue&_no_key_1=keyvalue2
 *                  
 *             如果默认动作路径为  main.ha
 *                  实际访问的应为 http://www.baidu.com/keyvalue/main.ha?_nokey_count=1&_no_key_0=keyvalue2
 *                  
 *                  
 * 2019-06-15 按照IFilter增加了过滤器初始化方法
 * 2019-08-24 由于request对象去掉了setPathTranslated方法
 * 2022-09-04 隔离了ServletApi，兼容新老Tomcat
 * 2022-09-05 修改了发现的错误
 *                  
 * @author 马宝刚
 * 2015年3月31日
 */
@ClassInfo({"2022-09-07 13:09","特殊URL处理过滤器"})
@BeanInfo({"specialurlfilter"})
@Running({"99"})
@Register({"filtervector"})
public class SpecialUrlFilter extends ABase implements IFilter {

    private String defaultAction = null;  //默认调用的动作
    private boolean basePathActionMode = true; //是否为根路径模式
    private String webBasePath = null; //网站根路径
    private String redirUrl = null; //全部重定向到指定的url中
    private boolean redir = false; //是否将全部请求重定向到指定url
    
    
    /**
     * 构造函数
     * @author 马宝刚
     */
    public SpecialUrlFilter() {
        super();
    }


    /**
     * 覆盖方法
     * 刘虻
     * 2015年3月31日
     */
    @Override
    public int getIndex() {
        return 0;
    }

    /**
     * 覆盖方法
     * 刘虻
     * 2015年3月31日
     */
    @Override
    public String getFilterActionExtName() {
        return "-";
    }
    
    /**
     * 设置是否重定向，为空的时候不重定向
     * @param redirStr 重定向url
     * 2015年5月18日
     * @author 马宝刚
     */
    public void setRedir(String redirStr) {
        if(redirStr==null || redirStr.length()<1) {
            redir = false;
            redirUrl = null;
        }else {
            redir = true;
            redirUrl = redirStr;
        }
    }
    
    
	/**
	 * 执行初始化
	 * @param bf         过滤器管理类
	 * @param config     Servlet配置信息类
	 * @throws Exception 异常（如果初始化发生异常，则放弃不再使用）
	 * 2019年6月15日
	 * @author MBG
	 */
	@Override
	public void init(BaseFilter bf, IFilterConfig config) throws Exception {
        if(webBasePath==null) {
            webBasePath = filesUtil.getAllFilePath("../../");
        }
	}
    
    /**
     * 设置网站根绝对路径（物理路径）
     * @param webBasePath 根绝对路径
     * 2015年4月9日
     * @author 马宝刚
     */
    public void setWebBasePath(String webBasePath) {
        this.webBasePath = webBasePath;
    }
    
    
    /**
     * 设置默认动作路径
     * @param defaultAction 默认动作路径
     * 2015年4月9日
     * @author 马宝刚
     */
    public void setDefaultAction(String defaultAction) {
        this.defaultAction = defaultAction;
        if(defaultAction!=null) {
            //如果开头不是/，则设置为非根路径模式
            basePathActionMode = defaultAction.startsWith("/");
        }
    }
    
    

    /**
     * 覆盖方法
     * 刘虻
     * 2015年3月31日
     */
    @Override
    public boolean doFilter(IRequestManager req, IResponseManager resp) throws Exception {
        if(redir) {
            if(redirUrl!=null && redirUrl.length()>0) {
                resp.sendRedirect(redirUrl);
                return true;
            }
        }
        if(defaultAction==null) {
            warning("=======================================The defaultAction is null===================================");
            return true;
        }
        //动作路径
        String servletPath = req.getServletPath();
        if(servletPath.length()<1 || "/".equals(servletPath)) {
            req.setServletPath(defaultAction);
        }else if(SFilesUtil.isFileExist(servletPath,webBasePath) && !basePathActionMode) {
            if(servletPath.endsWith("/")) {
            	req.setServletPath(servletPath+defaultAction);
            }else {
            	req.setServletPath(servletPath+"/"+defaultAction);
            }
        }else if(basePathActionMode) {
            if(servletPath.endsWith("/")) {
                //去掉末尾的/
                servletPath = servletPath.substring(1,servletPath.length()-1);
            }else {
                servletPath = servletPath.substring(1);
            }
            req.addQueryString(BaseUtil.swapString(servletPath,"/","&"));
            req.setServletPath(defaultAction);
        }else {
            if(servletPath.endsWith("/")) {
                //去掉末尾的/
                servletPath = servletPath.substring(1,servletPath.length()-1);
            }else {
                servletPath = servletPath.substring(1);
            }
            //分割每一级字符串
            String[] subPaths = BaseUtil.split(servletPath,"/");
            if(subPaths.length>0) {
                int index = 0; //层级
                String subPath = "/"+subPaths[index];
                while(SFilesUtil.isFileExist(subPath,webBasePath)) {
                    index++;
                    subPath += "/"+subPaths[index];
                }
                for(int i=index;i<subPaths.length;i++) {
                	req.addQueryString(subPaths[i]);
                }
                req.setServletPath(subPath+"/"+defaultAction);
            }else {
            	req.setServletPath(defaultAction);
            }
        }
        return false;
    }
    
    /**
     * 覆盖方法
     */
    @Override
    public void destroy() {}
}
